package neo.tetris.bean.model.tetris;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;

import neo.tetris.bean.model.tetris.Shape.Tetrominoes;

public class BoardPanel extends JPanel implements ActionListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	Timer timer;
	boolean isStarted = false;
	boolean isPaused = false;
	int curX = 0;
	int curY = 0;
	JLabel statusbar;
	Tetris tetris;

	public BoardPanel(TetrisFrame parent) {
		super();

		setFocusable(true);
		timer = new Timer(400, this);
		timer.start();
		tetris = new Tetris();
		statusbar = parent.getStatusBar();
		addKeyListener(new TAdapter());
	}

	public void actionPerformed(ActionEvent e) {
		if (tetris.tryMove(tetris.curPiece, curX, curY - 1)) {
			curY = curY - 1;
		} else {
			tetris.pieceDropped(curX, curY);
		}
		repaint();
	}

	int squareWidth() {
		return (int) getSize().getWidth() / tetris.boardWidth;
	}

	int squareHeight() {
		return (int) getSize().getHeight() / tetris.boardHeight;
	}

	public void start() {
		if (isPaused)
			return;

		isStarted = true;
		tetris.numLinesRemoved = 0;
		tetris.clearBoard();
		tetris.newPiece();
		curX = tetris.boardWidth / 2 + 1;
		curY = tetris.boardHeight - 1 + tetris.curPiece.minY();
		if (!tetris.tryMove(tetris.curPiece, curX, curY)) {
			tetris.curPiece.setShape(Tetrominoes.NoShape);
			timer.stop();
			isStarted = false;
			statusbar.setText("game over");
		}

		timer.start();
	}

	private void pause() {
		if (!isStarted)
			return;

		isPaused = !isPaused;
		if (isPaused) {
			timer.stop();
			statusbar.setText("paused");
		} else {
			timer.start();
			statusbar.setText(String.valueOf(tetris.numLinesRemoved));
		}
		repaint();
	}

	public void paint(Graphics g) {
		super.paint(g);

		Dimension size = getSize();
		int boardTop = (int) size.getHeight() - tetris.boardHeight * squareHeight();

		for (int i = 0; i < tetris.boardHeight; ++i) {
			for (int j = 0; j < tetris.boardWidth; ++j) {
				Tetrominoes shape = tetris.shapeAt(j, tetris.boardHeight - i - 1);
				if (shape != Tetrominoes.NoShape)
					drawSquare(g, 0 + j * squareWidth(), boardTop + i * squareHeight(), shape);
			}
		}

		if (tetris.curPiece.getShape() != Tetrominoes.NoShape) {
			for (int i = 0; i < 4; ++i) {
				int x = curX + tetris.curPiece.x(i);
				int y = curY - tetris.curPiece.y(i);
				drawSquare(g, 0 + x * squareWidth(), boardTop + (tetris.boardHeight - y - 1) * squareHeight(), tetris.curPiece.getShape());
			}
		}
	}

	private void drawSquare(Graphics g, int x, int y, Tetrominoes shape) {
		Color colors[] = { new Color(0, 0, 0), new Color(204, 102, 102), new Color(102, 204, 102), new Color(102, 102, 204), new Color(204, 204, 102), new Color(204, 102, 204),
				new Color(102, 204, 204), new Color(218, 170, 0) };

		Color color = colors[shape.ordinal()];

		g.setColor(color);
		g.fillRect(x + 1, y + 1, squareWidth() - 2, squareHeight() - 2);

		g.setColor(color.brighter());
		g.drawLine(x, y + squareHeight() - 1, x, y);
		g.drawLine(x, y, x + squareWidth() - 1, y);

		g.setColor(color.darker());
		g.drawLine(x + 1, y + squareHeight() - 1, x + squareWidth() - 1, y + squareHeight() - 1);
		g.drawLine(x + squareWidth() - 1, y + squareHeight() - 1, x + squareWidth() - 1, y + 1);
	}

	class TAdapter extends KeyAdapter {
		public void keyPressed(KeyEvent e) {

			if (!isStarted || tetris.curPiece.getShape() == Tetrominoes.NoShape) {
				return;
			}

			int keycode = e.getKeyCode();

			if (keycode == 'p' || keycode == 'P') {
				pause();
				return;
			}

			if (isPaused)
				return;

			switch (keycode) {
			case KeyEvent.VK_LEFT:
				Shape shiftShape = tetris.curPiece;
				int targetX = curX - 1;
				int targetY = curY;
				if (tetris.tryMove(shiftShape, targetX, targetY)) {
					repaint();
					tetris.curPiece = shiftShape;
					curX = targetX;
					curY = targetY;
				}
				break;
			case KeyEvent.VK_RIGHT:
				shiftShape = tetris.curPiece;
				targetX = curX + 1;
				targetY = curY;
				if (tetris.tryMove(shiftShape, targetX, targetY)) {
					repaint();
					tetris.curPiece = shiftShape;
					curX = targetX;
					curY = targetY;
				}
				break;
			case KeyEvent.VK_DOWN:
				shiftShape = tetris.curPiece.rotateRight();
				targetX = curX;
				targetY = curY;
				if (tetris.tryMove(shiftShape, targetX, targetY)) {
					repaint();
					tetris.curPiece = shiftShape;
					curX = targetX;
					curY = targetY;
				}
				break;
			case KeyEvent.VK_UP:
				shiftShape = tetris.curPiece.rotateLeft();
				targetX = curX;
				targetY = curY;
				if (tetris.tryMove(shiftShape, curX, curY)) {
					repaint();
					tetris.curPiece = shiftShape;
					curX = targetX;
					curY = targetY;
				}
				break;
			case KeyEvent.VK_SPACE:
				tetris.dropDown(curX, curY);
				repaint();
				break;
			case 'd':
			case 'D':
				if (tetris.tryMove(tetris.curPiece, curX, curY - 1)) {
					curY = curY - 1;
				} else {
					tetris.pieceDropped(curX, curY - 1);
				}
				repaint();
				break;
			}

		}
	}
}
